#ifndef _N_FORMAT_H_
#define _N_FORMAT_H_
#include"util.hpp"
#include"level.hpp"
#include"message.hpp"
#include<memory>
#include<ctime>
#include<vector>
#include<cassert>
#include<sstream>
#include<iostream>
namespace bitlog
{
    //先抽象出一个抽象格式化子项基类
    class Formatitem
    {
        public:
        using ptr = std::shared_ptr<Formatitem>;//智能指针类型，对于基类的管理
        virtual void format(std::ostream &out,const logmessage &message)=0;
    };
    class levelFormatitem:public Formatitem//等级子格式
    {
        public:
         void format(std::ostream &out,const logmessage &message) override//记住传入的是一个类
         {
            out<<Level::changestring(message._level);
         }
    };
    class messageFormatitem:public Formatitem//等级子格式
    {
        public:
          void format(std::ostream &out,const logmessage &message) override//记住传入的是一个类
         {
            out<<message._payload;
         }
    };

    class TimeFormatitem:public Formatitem//时间子格式
    {
        public:
        TimeFormatitem(const std::string &fmt = "%H%M%S"):time_format(fmt)
        {}//初始化构造函数，将子格式字符串填充好，有默认值
        void format(std::ostream &out,const logmessage &message) override//记住传入的是一个类
         {
            struct tm t;
            localtime_r(&message._ctime,&t);//将时间转化为本地时间打印的函数，将前面的时间戳转化为结构体中的数据存储起来
            char timetmp[32] = {0};//临时字符数组
            strftime(timetmp,31,time_format.c_str(),&t);//这个函数用于将struct tm格式中的时间
            //第一个参数是存储时间的字符数组，第二个参数是字符数组的最大长度，第三个参数是格式化字符串表明要吸取哪些参数，第四个参数是指针，用于指向struct tm 结构体
            out<<timetmp;
         }

        private:
        std::string time_format;//时间子格式字符串
    };

    class FileFormatitem:public Formatitem//文件名子格式
    {
        public:
          void format(std::ostream &out,const logmessage &message) override//记住传入的是一个类
         {
            out<<message._file;//直接输出文件名
         }
    };

    class LineFormatitem:public Formatitem//文件错误行数子格式
    {
        public:
           void format(std::ostream &out,const logmessage &message) override//记住传入的是一个类
         {
            out<<message._line;//直接输出文件名
         }
    };

    class ThreadFormatitem:public Formatitem//线程ID子格式
    {
        public:
           void format(std::ostream &out,const logmessage &message) override//记住传入的是一个类
         {
            out<<message._tid;
         }
    };

    class loggerFormatitem:public Formatitem//日志器子格式
    {
        public:
           void format(std::ostream &out,const logmessage &message) override//记住传入的是一个类
         {
            out<<message._logger;
         }
    };

    class TabFormatitem:public Formatitem//制表符子格式，用于输出Tab键
    {
        public:
           void format(std::ostream &out,const logmessage &message) override//记住传入的是一个类
         {
            out<<"\t";
         }
    };

    class ChangelineFormatitem:public Formatitem//换行子格式
    {
        public:
           void format(std::ostream &out,const logmessage &message) override//记住传入的是一个类
         {
            out<<"\n";
         }
    };

    class OtherFormatitem:public Formatitem//其他子格式
    {
        public:
        OtherFormatitem(const std::string str):_str(str)
        {}
           void format(std::ostream &out,const logmessage &message) override//记住传入的是一个类
         {
            out<<_str;
         }
         private:
         std::string _str;
    };
    
/*
标准格式化子字符串应该包含以下几项内容
%d日期  具体为{%H%M%S}
%f文件名
%p日志级别
%l行号
%m日志信息
%n换行
%T缩进
%c日志器名称
%t线程ID号
*/
    class Formatter//格式化器
    {
        public:
        using ptr=std::shared_ptr<Formatter>;
        Formatter(const std::string &pattern = "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n"):_pattern(pattern)
        {
           assert(messagepattern());
        }
        //格式化message字符串
        void format(std::ostream &out,logmessage &message)
        {
            for(auto &items:_items)
            {
                items->format(out,message);
            }
        }
        std::string format(logmessage &message)
        {
            std::stringstream ss;
            format(ss,message);
            return ss.str();
        }
        //规则字符串解析
        bool messagepattern()
        {
            //1.对格式化字符串进行解析
            //遇到百分号，看看后面有没有百分号（担心是转义字符），如果不是，代表这个是格式化字符
            //在格式化字符之后，看有没有花括号
            size_t pos=0;
            std::vector<std::pair<std::string,std::string>>format_order;//不太理解
            std::string key,val;
            while(pos<_pattern.size())
            {
                //若不是百分号，那么就是原始字符串
                if(_pattern[pos]!='%')
                {
                    val.push_back(_pattern[pos++]);
                    continue;
                }
                //走到下面代表pos位置是百分号字符，%%为转义字符，先处理这种情况
                if(pos+1<_pattern.size()&&_pattern[pos+1]=='%')
                {
                    val.push_back('%');
                    pos+=2;
                    continue;
                }
                //处理好转义字符了，代表%后面是格式化字符，处理格式化字符
               if(pos<_pattern.size()&&val.empty()==false)
               {
                format_order.push_back(std::make_pair("",val));
                val.clear();
               }
                pos+=1;
                if(pos==_pattern.size())
                {
                    std::cout<<"没有对应的格式化字符"<<std::endl;
                    return false;
                }
                key=_pattern[pos];
                //先处理%符号后面产生{}的问题
                pos+=1;
                if(pos<_pattern.size()&&_pattern[pos]=='{')
                {
                    pos+=1;
                    while(pos<_pattern.size()&&_pattern[pos]!='}')
                    {
                        val.push_back(_pattern[pos]);
                        pos++;
                    }
                    if(pos==_pattern.size())
                    {
                        std::cout<<"子格式{}匹配出错！！"<<std::endl;
                        return false;//没有找到
                    }
                    pos+=1;//走到右括号的下一位置，处理新的字符串
                }
                format_order.push_back(std::make_pair(key,val));
                key.clear();
                val.clear();
            }
            //根据得到的数据初始化格式化子项数组成员
            for(auto &it:format_order)
            {
                _items.push_back(createitem(it.first,it.second));
            }
            return true;
        }
        private:
        Formatitem::ptr createitem(const std::string &key,const std::string &val)
        {
            if(key=="d") return std::make_shared<TimeFormatitem>(val);
            if(key=="t") return std::make_shared<ThreadFormatitem>();
            if(key=="c") return std::make_shared<loggerFormatitem>();
            if(key=="f") return std::make_shared<FileFormatitem>();
            if(key=="l") return std::make_shared<LineFormatitem>();
            if(key=="p") return std::make_shared<levelFormatitem>();
            if(key=="T") return std::make_shared<TabFormatitem>();
            if(key=="m") return std::make_shared<messageFormatitem>();
            if(key=="n") return std::make_shared<ChangelineFormatitem>();
            if(key=="") return std::make_shared<OtherFormatitem>(val);
            std::cout<<"没有对应的格式化字符：%"<<key<<std::endl;
            abort();
            return Formatitem::ptr();
        }
        std::vector<Formatitem::ptr> _items;//代表标准格式化字符串
        std::string _pattern;
    };
}



#endif